// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: t -*-

/*
mySerial1.cpp

Author:     Uwe Gartmann

This firmware is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
*/
/// Definitions

// Use same buffer size for RX and TX
#define BUFFER_SIZE 256
#define BUFFER_MASK (BUFFER_SIZE-1)

// check if the buffer size is the power of 2
#if ( BUFFER_SIZE & BUFFER_MASK )
#    error buffer size is not a power of 2
#endif

/// Includes
extern "C" {
	#include <avr/io.h>
	#include <avr/interrupt.h>
	#include "wiring.h"
}
#include <mySerial1.h>

/// Declarations
volatile uint8_t t0Bcntr = 0;
volatile uint8_t DataReceived = 0;

//define ringbuffer
struct ring_buffer {
  unsigned char buffer[BUFFER_SIZE];
  volatile unsigned char head;
  volatile unsigned char tail;
};

// create buffer for rx and tx
ring_buffer rx1_buffer = { { 0 }, 0, 0 };
ring_buffer tx1_buffer = { { 0 }, 0, 0 };

ISR(USART1_RX_vect)		//################################################
{
	unsigned char c = UDR1;
	unsigned char i = (rx1_buffer.head + 1);
	i &= BUFFER_MASK;
	if (i != rx1_buffer.tail)
	{
		rx1_buffer.buffer[rx1_buffer.head] = c;
		rx1_buffer.head = i;
	}
	t0Bcntr = 0; // reset counter
}

ISR(USART1_UDRE_vect)	//################################################
{
    if (tx1_buffer.head == tx1_buffer.tail) {
        // Buffer is empty, disable the interrupt
        UCSR1B &= ~(1<<UDRIE1);
    } else {
    	UDR1 = tx1_buffer.buffer[tx1_buffer.tail];
    	tx1_buffer.tail = (tx1_buffer.tail + 1);
		tx1_buffer.tail &= BUFFER_MASK;
    }
}

ISR(TIMER0_COMPB_vect) // Timer 0 CompB event
// This timer interrupt delays sending the next frame to the Jeti Box (in ms)
// The main function of timer0 belongs to millis() 
{
	switch (t0Bcntr) {
		case 0:
			++t0Bcntr;
			// data transmission ongoing, hold on
			DataReceived = 0;
			break;
		case 10: 
			++t0Bcntr;
			// signal valid data
			DataReceived = 1;
			break;
		case 200:
			++t0Bcntr;
			// data 100ms old, depricate data
			DataReceived = 0;
			t0Bcntr = 255; 
			break;
		case 255:
			// data depricated
			break;
		default: 
			++t0Bcntr;
	}
}


mySerial1::mySerial1()
{
// Class constructor
}

// Public Methods //////////////////////////////////////////////////////////////
void mySerial1::begin(long BAUD1)
{
#ifndef F_CPU
	#define F_CPU 16000000
#endif
#define _UBRR1 (F_CPU/8/BAUD1-1)	//when U2X0 is not set use divider 16 instead of 8

	// Set baudrate
	UCSR1A = (1<<U2X1); //U2X0 enabled!
	UBRR1H=(_UBRR1>>8);   //high byte
	UBRR1L=_UBRR1;      //low byte

	// Set frame format: 8data, no parity, 1stop bit
	UCSR1C = (0<<UMSEL10)|(0<<UPM10)|(0<<USBS1)|(3<<UCSZ10);

	// Enable receiver and transmitter
	UCSR1B = (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1);
	
	OCR0B = 170;			// set interrupt between overflow interrupts
	TIMSK0 |= _BV(OCIE0B);	// enable OCR0B overflow interrupt
	
}

void mySerial1::end()
{
	// Enable receiver and transmitter
	UCSR1B = (0<<RXEN1)&(0<<TXEN1)&(0<<RXCIE1);
}

int mySerial1::available(void)
{
	int c =  BUFFER_SIZE + rx1_buffer.head - rx1_buffer.tail;
	return c %= BUFFER_SIZE;
 }

int mySerial1::read(void)
{
	// if the head isn't ahead of the tail, we don't have any characters
	if (rx1_buffer.head == rx1_buffer.tail) {
		return -1;
	} else {
		unsigned char c = rx1_buffer.buffer[rx1_buffer.tail];
		rx1_buffer.tail = (rx1_buffer.tail + 1);
		rx1_buffer.tail &= BUFFER_MASK;
		return c;
  }
}

void mySerial1::flush()
{
  // don't reverse this or there may be problems if the RX interrupt
  // occurs after reading the value of rx_buffer_head but before writing
  // the value to rx_buffer_tail; the previous value of rx_buffer_head
  // may be written to rx_buffer_tail, making it appear as if the buffer
  // don't reverse this or there may be problems if the RX interrupt
  // occurs after reading the value of rx_buffer_head but before writing
  // the value to rx_buffer_tail; the previous value of rx_buffer_head
  // may be written to rx_buffer_tail, making it appear as if the buffer
  // were full, not empty.
  rx1_buffer.head = rx1_buffer.tail;
  //_tx_buffer->head = _tx_buffer->tail;
}

void mySerial1::write(uint8_t c)
{
	unsigned char i = (tx1_buffer.head + 1);
	unsigned char _tail = tx1_buffer.tail;
	//if (_tail != tx_buffer.tail) {
	//	_tail = tx_buffer.tail;
	//}
	i &= BUFFER_MASK;
	if (i != _tail)
	{
		tx1_buffer.buffer[tx1_buffer.head] = c;
		tx1_buffer.head = i;
	}
	UCSR1B |= (1<<UDRIE1); // Enable Data Register Empty interrupt
}

uint8_t mySerial1::datareceived(void) {
	uint8_t x = DataReceived;
	if (x == 1) {
		// data processed
		DataReceived = 0;
	}
	return x;
}




